﻿using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Text;

namespace PronosGestor
{
    public static class PronosGestorV2
    {
        private const string RecapParticipants = "Classt";
        private const string RecapAllPronos = "Recap";
        private const string RecapChauvins = "Classement des chauvins";
        private const string MainStringConnection =
            "Provider=Microsoft.ACE.OLEDB.12.0; Data Source = ePronos.xlsx" +
            @"; Extended Properties =""Excel 12.0;HDR=NO;IMEX=1"";";
        private const string WriteMainStringConnection =
            "Provider=Microsoft.ACE.OLEDB.12.0; Data Source = ePronos.xlsx" +
            @"; Extended Properties =""Excel 12.0;HDR=NO;IMEX=1"";";

        public static StreamWriter log = new StreamWriter("log.txt", false, Encoding.GetEncoding(1252));
        private static StreamReader config = new StreamReader("Config.ini", Encoding.GetEncoding(1252));

        private static string fichierPronos;

        private static List<Participant> participants;
        private static List<JourneeJouee> journees;
        private static StatsGenerales statsGenerales;
        private static List<string> equipes;

        #region public

        /// <summary>
        /// Initialise tous les fichiers nécessaires
        /// </summary>
        public static void Init()
        {
            var configlines = new List<string>();
            try
            {
                while (!config.EndOfStream)
                {
                    configlines.Add(config.ReadLine());
                }

            }
            catch (Exception)
            {
                Log("Fichier Config.ini introuvable");
            }

            // récupération du chemin du fichier global de pronos
            configlines = configlines.Where(x => !x.StartsWith("!")).ToList();
            fichierPronos = configlines.Find(x => x.Contains("pronosFilePath")).Split('=')[1];

            // Remplit participants
            InitParticipants();

            // Remplit journees
            InitJournees();

            // Remplit JourneesPronostiquees dans Participant
            InitPronostics();

            // Calcul complet des statistiques
            CalculerStats();

            // Alimentation des stats dans l'excel de sortie
            AlimenterExcelStats();
        }

        #endregion

        #region private

        private static void Log(string message)
        {
            log.WriteLine(DateTime.Now.ToString() + " - " + message);
        }

        private static void InitParticipants()
        {
            participants = new List<Participant>();

            fichierPronos = @"E:\VS2010\_Humanis\OP_PronosGestor\Bin\ePronos.xlsx";
            string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source =" + fichierPronos;
            connectionString += @"; Extended Properties =""Excel 12.0;HDR=NO;IMEX=1"";";

           //string connectionString = @"Provider=Microsoft.ACE.OLEDB.14.0;Data Source=ePronos.xlsx;HDR=yes;Format=xlsx;";
            //string connectionString = @"Provider=Microsoft.ACE.OLEDB.14.0;Data Source=E:\VS2010\_Humanis\OP_PronosGestor\Bin\ePronos.xlsx;HDR=YES";

            OleDbConnection connection = new OleDbConnection(connectionString);

            string cmdText;
            OleDbCommand command;
            OleDbDataReader reader;

            // Gestion des joueurs
            InitJoueurs(connection, out cmdText, out command, out reader);

            // Gestion des équipes préférées
            InitEquipesPreferees(connection, ref cmdText, ref command, ref reader);
        }

        private static void InitJournees()
        {
            journees = new List<JourneeJouee>();
            equipes = new List<string>();

            OleDbConnection connection;
            OleDbDataReader reader;
            PreparerReader(out connection, out reader, RecapAllPronos);

            reader.Read();

            bool continuer = true;
            int i = 1;
            while (continuer)
            {
                if (i > 38)
                    continuer = false;
                else
                {
                    var journee = new JourneeJouee() { IDJournee = i };
                    for (int j = 0; j < 10; j++)
                    {
                        reader.Read();
                        journee.MatchsJournee.Add(new MatchJoue()
                        {
                            EquipeDomicile = Convert.ToString(reader[1]).Trim(),
                            EquipeExterieur = Convert.ToString(reader[4]).Trim(),
                            ResultatMatch = new Resultat()
                            {
                                ScoreDomicile = Convert.ToString(reader[2]).Trim(),
                                ScoreExterieur = Convert.ToString(reader[3]).Trim()
                            },
                            IDMatch = j + 1
                        });

                        // Pour la première journée, on rmeplit la liste des équipes
                        if (i == 1)
                            equipes.AddRange(new List<string> { Convert.ToString(reader[1]).Trim(), Convert.ToString(reader[4]).Trim() });
                    }

                    // Si la journée n'est pas complète, on ne l'ajoute pas.
                    if (journee.EstJourneeComplete())
                    {
                        journees.Add(journee);
                        i++;
                    }
                    else
                        break;
                }
            }

            LibererReaderEtConnexion(connection, reader);
        }

        private static void InitPronostics()
        {
            OleDbConnection connection;
            OleDbDataReader reader;
            PreparerReader(out connection, out reader, RecapAllPronos);

            reader.Read();

            bool continuer = true;
            int i = 1;
            while (continuer)
            {
                if (i > journees.Count)
                    continuer = false;
                else
                {
                    // Nouvelle journée : création de la journée pour chaque participant
                    foreach (var participant in participants)
                    {
                        participant.JourneesPronostiquees.Add(new JourneePronostiquee() { IDJournee = i });
                    }

                    // Parcours des 10 matchs pronostiqués
                    for (int j = 0; j < 10; j++)
                    {
                        reader.Read();

                        // Parcours de chaque participant pour le match en cours
                        for (int k = 0; k < participants.Count; k++)
                        {
                            // recherche du match correspondant
                            var matchCorrespondant = journees.Where(x => x.IDJournee == i).First().MatchsJournee.Where(x => x.IDMatch == j + 1).First();

                            var unMatchPronostique = new MatchPronostique()
                            {
                                EquipeDomicile = matchCorrespondant.EquipeDomicile,
                                EquipeExterieur = matchCorrespondant.EquipeExterieur,
                                ResultatMatch = new Resultat()
                                {
                                    ScoreDomicile = Convert.ToString(reader[5 + 3 * k]).Trim(),
                                    ScoreExterieur = Convert.ToString(reader[6 + 3 * k]).Trim()
                                },
                                IDMatch = matchCorrespondant.IDMatch
                            };

                            // Alimentation du match
                            participants[k].JourneesPronostiquees[i - 1].MatchsJournee.Add(unMatchPronostique);

                            // Alimentation pour le calcul de la cote du match correspondant
                            matchCorrespondant.CoteMatch.AlimenterCoteSelonPronostic(unMatchPronostique.ResultatMatch);
                        }
                    }
                }
                i++;
            }

            LibererReaderEtConnexion(connection, reader);
        }

        private static void CalculerStats()
        {
            statsGenerales = new StatsGenerales();

            // Parcours des journées
            for (int i = 0; i < journees.Count; i++)
            {
                var journeeEnCours = journees[i];

                // Parcours des pronostiqueurs
                for (int j = 0; j < participants.Count; j++)
                {
                    // récupération de la journée pronostiquée
                    var journeePronostiqueeEnCours = participants[j].JourneesPronostiquees[i];

                    // Parcours de matchs pronostiqués
                    foreach (var matchPronostique in journeePronostiqueeEnCours.MatchsJournee)
                    {
                        // vérification du résultat
                        if (matchPronostique.ResultatMatch.TypeResultat != 'X')
                        {
                            if (matchPronostique.ResultatMatch.TypeResultat == journeeEnCours.MatchsJournee[matchPronostique.IDMatch - 1].ResultatMatch.TypeResultat)
                            {
                                journeePronostiqueeEnCours.NombreResultatsBons += 1;
                                journeePronostiqueeEnCours.Points += 2;
                                // vérification du score exact
                                if (matchPronostique.ResultatMatch.ScoreDomicile == journeeEnCours.MatchsJournee[matchPronostique.IDMatch - 1].ResultatMatch.ScoreDomicile &&
                                    matchPronostique.ResultatMatch.ScoreExterieur == journeeEnCours.MatchsJournee[matchPronostique.IDMatch - 1].ResultatMatch.ScoreExterieur)
                                {
                                    journeePronostiqueeEnCours.NombreScoresExacts += 1;
                                    journeePronostiqueeEnCours.Points += 1;
                                }
                            }
                            // calcul des gains associés (on enlève 1 qui est la mise)
                            journeePronostiqueeEnCours.GainsVirtuels += journeeEnCours.MatchsJournee[matchPronostique.IDMatch - 1].Gain(matchPronostique) - 1;
                        }
                    }
                }
            }

            // classements
            statsGenerales.ConstituerClassementVainqueurs(participants, journees);
            statsGenerales.ConstituerClassementGeneral(participants);
            statsGenerales.ConstituerClassementGeneralParJournee(participants, journees);
            statsGenerales.ConstituerClassementsEquipesParPronos(participants, equipes, journees.Count());

            // affichage classement
            LogRecords();
        }

        private static void LogRecords()
        {
            // records
            var test = statsGenerales.MeilleureVictoire;
            var test2 = statsGenerales.PlusDeResultatsTrouvesJournee;
            var test3 = statsGenerales.PlusDeScoresExtactsTrouvesJournee;
            var test4 = statsGenerales.PlusGrosGainVirtuelJournee;

            log.WriteLine("*** RECORDS ***");

            log.WriteLine(" Meilleure victoire en journée : ");
            foreach (var item in statsGenerales.MeilleureVictoire.Key)
            {
                log.WriteLine("     " + item + " - " + statsGenerales.MeilleureVictoire.Value + " points.");
            }

            log.WriteLine(" Plus de résultats trouvés en journée : ");
            foreach (var item in statsGenerales.PlusDeResultatsTrouvesJournee.Key)
            {
                log.WriteLine("     " + item + " - " + statsGenerales.PlusDeResultatsTrouvesJournee.Value + " résultats trouvés.");
            }

            log.WriteLine(" Plus de scores exacts trouvés en journée : ");
            foreach (var item in statsGenerales.PlusDeScoresExtactsTrouvesJournee.Key)
            {
                log.WriteLine("     " + item + " - " + statsGenerales.PlusDeScoresExtactsTrouvesJournee.Value + " scores exacts.");
            }

            log.WriteLine(" Plus gros gain virtuel en journée (mise de 1€ par match pronostiqué) : ");
            foreach (var item in statsGenerales.PlusGrosGainVirtuelJournee.Key)
            {
                log.WriteLine("     " + item + " - " + statsGenerales.PlusGrosGainVirtuelJournee.Value.ToString("#.##") + " €.");
            }
        }

        private static void AlimenterExcelStats()
        {
            ExcelClassementGeneral();

            ExcelClassementParJournees();

            ExcelClassementDesVainqueurs();

            ExcelClassementEquipesPronos();
        }

        private static void ExcelClassementGeneral()
        {
            // Classement général   
            using (var sR = new StreamWriter("Classement général.csv", false, Encoding.GetEncoding(1252)))
            {
                EcrireEnteteExcel(sR, "Rang;Joueur;Points;Efficience;Victoires;Journées Complètes;Total Résultats Bons;Scores Exacts;Gains Virtuels;" +
                "Total Pronostics;Moyenne points/journée");

                int cmpt = 1;
                foreach (var position in statsGenerales.Classement)
                {
                    sR.WriteLine(
                        cmpt + ";" +
                        position.Key + ";" +
                        position.Value.Points.ToString() + ";" +
                        position.Value.CalculerEfficience().ToString("#.## %") + ";" +
                        position.Value.NombreVictoires + ";" +
                        position.Value.NombreJourneesCompletes + ";" +
                        position.Value.NombreResultatsBons.ToString() + ";" +
                        position.Value.NombreScoresExacts.ToString() + ";" +
                        position.Value.GainsVirtuels.ToString("#.##") + ";" +
                        position.Value.NombrePronostics + ";" +
                        position.Value.CalculerMoyennePointsParJournee().ToString("#.##")
                        );
                    cmpt++;
                }
            }
        }

        private static void ExcelClassementParJournees()
        {
            using (var sR = new StreamWriter("Classement journéees.csv", false, Encoding.GetEncoding(1252)))
            {
                // Classements des journées         
                foreach (var journee in journees)
                {
                    sR.WriteLine("Journée " + journee.IDJournee);

                    EcrireEnteteExcel(sR, "Rang;Joueur;Points;Efficience;Total Résultats Bons;Scores Exacts;Gains Virtuels;Total Pronostics");

                    int cmpt = 1;
                    foreach (var position in statsGenerales.ClassementsJournees[journee.IDJournee - 1])
                    {
                        // Gestion d'une journée non jouée
                        if (position.Value.NombrePronostics == 0)
                            sR.WriteLine(
                                cmpt + ";" +
                                position.Key + ";" +
                                "N'a pas joué");
                        else
                        {
                            sR.WriteLine(
                                cmpt + ";" +
                                position.Key + ";" +
                                position.Value.Points.ToString() + ";" +
                                position.Value.CalculerEfficience().ToString("#.## %") + ";" +
                                position.Value.NombreResultatsBons.ToString() + ";" +
                                position.Value.NombreScoresExacts.ToString() + ";" +
                                position.Value.GainsVirtuels.ToString("#.##") + ";" +
                                position.Value.NombrePronostics
                                );
                        }
                        cmpt++;
                    }

                    sR.WriteLine("");
                }
            }
        }

        private static void ExcelClassementDesVainqueurs()
        {
            // Classement des vainqueurs 
            using (var sR = new StreamWriter("Classement victoires.csv", false, Encoding.GetEncoding(1252)))
            {
                EcrireEnteteExcel(sR, "Rang;Joueur;Victoires");

                int cmpt = 1;
                foreach (var position in statsGenerales.ClassementVainqueurs)
                {
                    sR.WriteLine(
                        cmpt + ";" +
                        position.Key + ";" +
                        position.Value);
                    cmpt++;
                }
            }
        }

        private static void ExcelClassementEquipesPronos()
        {
            using (var sR = new StreamWriter("Classement equipes.csv", false, Encoding.GetEncoding(1252)))
            {
                // Classements des journées         
                foreach (var joueur in participants)
                {
                    sR.WriteLine("Joueur " + joueur.nom);

                    EcrireEnteteExcel(sR, "Rang;Equipe;Matchs Joues;Points;Diff;Victoires;Nuls;Defaites;Buts Pour;Buts Contre");

                    int cmpt = 1;
                    // récupération du classement du joueur
                    var classement = statsGenerales.ClassementEquipesPronos[joueur.nom];
                    // tri du classement : points -> diff -> buts marqués -> buts encaissés
                    var sortedRank = classement.OrderByDescending(x => x.Points).ThenByDescending(x => x.GoalAverage).ThenBy(x => x.ButsEncaisses);

                    foreach (var position in sortedRank)
                    {
                        sR.WriteLine(
                                cmpt + ";" +
                                position.Equipe + ";" +
                                position.MatchsJoues + ";" +
                                position.Points.ToString() + ";" +
                                position.GoalAverage.ToString() + ";" +
                                position.Victoires.ToString() + ";" +
                                position.Nuls.ToString() + ";" +
                                position.Defaites.ToString() + ";" +
                                position.ButsMarques.ToString() + ";" +
                                position.ButsEncaisses.ToString()
                                );
                        cmpt++;
                    }

                    sR.WriteLine("");
                }
            }
        }

        #region Membres de mécanique interne

        private static void EcrireEnteteExcel(StreamWriter sR, string entete)
        {
            sR.WriteLine(entete);
        }

        private static void RecapDetailleMatchs()
        {
            // récap précis
            foreach (var participant in participants)
            {
                log.WriteLine("*** JOUEUR : " + participant.nom + " ( " + participant.TotalPoints() + " Points ) ***");
                foreach (var journee in participant.JourneesPronostiquees)
                {
                    log.WriteLine(" Journee : " + journee.IDJournee);

                    foreach (var match in journee.MatchsJournee)
                    {
                        log.WriteLine("     Match : " + match.IDMatch + " - " + match.ResultatMatch.TypeResultat.ToString() +
                            " { " + match.ResultatMatch.ScoreDomicile + " - " + match.ResultatMatch.ScoreExterieur + " } ");
                    }

                    log.WriteLine(" Points remportés : " + journee.Points);
                }
            }
        }

        private static void LibererReaderEtConnexion(OleDbConnection connection, OleDbDataReader reader)
        {
            reader.Close();
            connection.Close();
        }

        private static void PreparerReader(out OleDbConnection connection, out OleDbDataReader reader,
            string feuille)
        {
            //fichierPronos = @"E:\2012-2013\e-Pronos Ligue 1 Saison 2012-2013102.xlsx";
            //fichierPronos = "Pronos_w.xlsx";
            //string connectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source =" + fichierPronos;
            //connectionString += @"; Extended Properties =""Excel 12.0;HDR=NO;IMEX=1"";";
            connection = new OleDbConnection(MainStringConnection);

            string cmdText;
            OleDbCommand command;


            cmdText = "SELECT * FROM [" + feuille + "$]";
            command = new OleDbCommand(cmdText, connection);

            command.Connection.Open();
            reader = command.ExecuteReader();
        }

        private static void InitEquipesPreferees(OleDbConnection connection, ref string cmdText, ref OleDbCommand command, ref OleDbDataReader reader)
        {
            cmdText = "SELECT * FROM [" + RecapChauvins + "$]";
            command = new OleDbCommand(cmdText, connection);

            command.Connection.Open();
            reader = command.ExecuteReader();

            if (reader.HasRows)
            {
                for (int i = 0; i < 2; i++)
                {
                    reader.Read();
                }

                bool fin = false;
                while (!fin)
                {
                    reader.Read();
                    if (Convert.ToString(reader[0]).Trim() == "")
                        fin = true;
                    else
                    {
                        // récupération des infos
                        var joueur = Convert.ToString(reader[0]).Trim();
                        var equipe = Convert.ToString(reader[1]).Trim();

                        // alimentation de la liste des participants
                        participants.Where(x => x.nom == joueur).First().equipePreferee = equipe;
                    }
                }
            }

            reader.Close();
            connection.Close();
        }

        private static void InitJoueurs(OleDbConnection connection, out string cmdText, out OleDbCommand command, out OleDbDataReader reader)
        {
            cmdText = "SELECT * FROM [" + RecapParticipants + "$]";
            command = new OleDbCommand(cmdText, connection);

            command.Connection.Open();
            reader = command.ExecuteReader();

            if (reader.HasRows)
            {
                for (int i = 0; i < 10; i++)
                {
                    reader.Read();
                }

                bool fin = false;
                while (!fin)
                {
                    reader.Read();
                    if (Convert.ToString(reader[14]).Trim() == "")
                        fin = true;
                    else
                        participants.Add(new Participant() { nom = Convert.ToString(reader[14]).Trim() });
                }
                reader.Read();
            }

            reader.Close();
            connection.Close();
        }

        #endregion

        #endregion
    }
}

